package com.ruoyi.ljx.controller;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.ljx.domain.Order;
import com.ruoyi.ljx.model.Result;
import com.ruoyi.ljx.websocket.OrderChanel;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.ljx.domain.TbDriver;
import com.ruoyi.ljx.service.ITbDriverService;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.page.TableDataInfo;

/**
 * 司机Controller
 * 
 * @author wuxiao
 * @date 2024-12-24
 */
@RestController
@RequestMapping("/driver")
@Slf4j
public class TbDriverController extends BaseController
{
    @Autowired
    private ITbDriverService tbDriverService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Value("${gaode.webKey}")
    private String gaodeKey;

    /**
     * 查询司机列表
     */
//    @RequiresPermissions("ljx:ljx:list")
    @GetMapping("/list")
    public TableDataInfo list(TbDriver tbDriver)
    {
        startPage();
        List<TbDriver> list = tbDriverService.selectTbDriverList(tbDriver);
        return getDataTable(list);
    }

    /**
     * 导出司机列表
     */
//    @RequiresPermissions("ljx:ljx:export")
    @Log(title = "司机", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, TbDriver tbDriver)
    {
        List<TbDriver> list = tbDriverService.selectTbDriverList(tbDriver);
        ExcelUtil<TbDriver> util = new ExcelUtil<TbDriver>(TbDriver.class);
        util.exportExcel(response, list, "司机数据");
    }

//    /**
//     * 获取司机详细信息
//     */
//    @RequiresPermissions("ljx:ljx:query")
//    @GetMapping(value = "/{driverId}")
//    public AjaxResult getInfo(@PathVariable("driverId") Long driverId)
//    {
//        return AjaxResult.success(tbDriverService.selectTbDriverByDriverId(driverId));
//    }

    /**
     * 新增司机
     */
//    @RequiresPermissions("ljx:ljx:add")
    @Log(title = "司机", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody TbDriver tbDriver)
    {
        return toAjax(tbDriverService.insertTbDriver(tbDriver));
    }

    /**
     * 修改司机
     */
//    @RequiresPermissions("ljx:ljx:edit")
    @Log(title = "司机", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody TbDriver tbDriver)
    {
        return toAjax(tbDriverService.updateTbDriver(tbDriver));
    }

    /**
     * 删除司机
     */
//    @RequiresPermissions("ljx:ljx:remove")
    @Log(title = "司机", businessType = BusinessType.DELETE)
	@DeleteMapping("/{driverIds}")
    public AjaxResult remove(@PathVariable Long[] driverIds)
    {
        return toAjax(tbDriverService.deleteTbDriverByDriverIds(driverIds));
    }


    /**
     * 审批司机入驻申请
     */
//    @RequiresPermissions("ljx:ljx:approve")
    @GetMapping(value = "/{driverId}")
    public AjaxResult approveWithdraw(@PathVariable("driverId") Long driverId)
    {
        return toAjax(tbDriverService.approveWithdraw(driverId));
    }



    /**
     * 获取距离地图中心半径2.5公里内的司机
     * @param longitude
     * @param latitude
     * @return
     */
    @GetMapping("/location")
    public List<TbDriver> getDriverLocation(String longitude, String latitude){

        // 设置检索范围
        Point point = new Point(Double.parseDouble(longitude), Double.parseDouble(latitude));
        Circle circle = new Circle(point, new Distance(2.5, Metrics.KILOMETERS));
        // 定义返回结果参数，如果不指定默认只返回content即保存的member信息
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
                .newGeoRadiusArgs().includeDistance().includeCoordinates()
                .sortAscending();
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius("beijing-driver-geo", circle, args);
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = results.getContent();

        List<TbDriver> driverList = new ArrayList<>();
        if(list.size() > 0){
            for(GeoResult<RedisGeoCommands.GeoLocation<String>> obj : list){
                RedisGeoCommands.GeoLocation<String> content = obj.getContent();
                String carCode = content.getName();
                Point point1 = content.getPoint();
                double x = point1.getX();
                double y = point1.getY();

                TbDriver driverLocation = new TbDriver();
                driverLocation.setCarCode(carCode);
                driverLocation.setLongitude(String.valueOf(x));
                driverLocation.setLatitude(String.valueOf(y));
                driverList.add(driverLocation);
            }
        }
        return driverList;
    }


    @PostMapping("/order")
    public Result createOrder(@RequestBody Order order) throws ParseException, IOException {

        String carTime = order.getCarTime().replace("T", " ");
        order.setCarTime(carTime);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date carTimeDate = sdf.parse(carTime);


        long current = System.currentTimeMillis();
        long timeDiffMin = (carTimeDate.getTime() - current)/(1000*60);

        log.info("起点:{},终点:{},距订单开始:{}分钟",order.getName1(),order.getName2(),timeDiffMin);

        //调用高德webAPI进行路线规划
        String url ="https://restapi.amap.com/v3/direction/driving?key="+gaodeKey;

        url += "&origin="+order.getLongitude1()+","+order.getLatitude1();
        url += "&destination="+order.getLongitude2()+","+order.getLatitude2();
        url += "&strategy=4";
        url += "&extensions=base";


        HttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = httpClient.execute(httpGet);
        String responseJSON = EntityUtils.toString(response.getEntity(), "UTF-8");
        System.out.println(responseJSON);
        //解析返回结果，获取总路程和预估时间
        Map responseMap = JSONObject.parseObject(responseJSON, Map.class);
        String status = (String) responseMap.get("status");
        if(!status.equals("1")){
            return new Result(false,null,"路线规划失败:"+responseMap.get("info"));
        }

        Map route = (Map) responseMap.get("route");
        List<Map> paths = (List<Map>) route.get("paths");
        Map pathObj = paths.get(0);
        double distance = Math.ceil(Double.parseDouble((String) pathObj.get("distance")) / 1000);
        double duration = Math.ceil(Double.parseDouble((String) pathObj.get("duration"))/60);
        log.info("总路程:{}公里,预估耗时:{}分钟",distance,duration);

        //订单入库
        Snowflake snowflake = new Snowflake(1,1);
        String id = snowflake.nextId()+"";
        order.setId(id);
        order.setDuration(duration);
        order.setDistance(distance);

        //计算预估金额

        //  2.5公里    20分钟   =  13 + （20-9）*0.7

        BigDecimal price = new BigDecimal("13");
        if(distance>3){
            price = price.add((new BigDecimal(distance).subtract(new BigDecimal("3")).multiply(new BigDecimal("1.6"))));
        }
        if(duration>9){
            price = price.add((new BigDecimal(duration).subtract(new BigDecimal("9"))).multiply(new BigDecimal("0.7")));
        }
        order.setPrice(price);

        //缓存订单信息
        redisTemplate.opsForValue().set("order:"+id,JSONObject.toJSONString(order));

        //orderService.saveOrder(order);

        if(timeDiffMin<=30){
            //即时单
            //推送给距离订单起点2公里内的司机
            // 设置检索范围
            Point point = new Point(Double.parseDouble(order.getLongitude1()), Double.parseDouble(order.getLatitude1()));
            Circle circle = new Circle(point, new Distance(2, Metrics.KILOMETERS));
            // 定义返回结果参数，如果不指定默认只返回content即保存的member信息
            RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
                    .newGeoRadiusArgs().includeDistance().includeCoordinates()
                    .sortAscending();
            GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius("beijing-driver-geo", circle, args);
            List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = results.getContent();

            //创建一个司机集合用来装符合要求的司机
            List<TbDriver> driverList = new ArrayList<>();
            if(list.size() > 0){
                for(GeoResult<RedisGeoCommands.GeoLocation<String>> obj : list){
                    RedisGeoCommands.GeoLocation<String> content = obj.getContent();
                    String carCode = content.getName();
                    Point point1 = content.getPoint();
                    double x = point1.getX();
                    double y = point1.getY();

                    TbDriver driverLocation = new TbDriver();
                    driverLocation.setCarCode(carCode);
                    driverLocation.setLongitude(String.valueOf(x));
                    driverLocation.setLatitude(String.valueOf(y));
                    driverList.add(driverLocation);
                }
            }

            for (TbDriver driverLocation : driverList) {
                String carCode = driverLocation.getCarCode();
                System.out.println(carCode);
                OrderChanel.sendMessage(carCode,JSONObject.toJSONString(order));
            }
            //创建1分钟的延迟消息
            log.info("开始计时30秒,{}",new Date());
            rabbitTemplate.convertAndSend("taxi-order-delayEx", "", id, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    message.getMessageProperties().setDelay(30*1000);
                    return message;
                }
            });

        }else{
            //预约单:直接存入订单大厅，若行程开始前30分钟无人接单则强制派单
            //订单缓存到redis中，并计算订单开始前30分钟时间，创建延迟消息，订单开始前30分钟
            redisTemplate.opsForList().leftPush("beijing-order",JSONObject.toJSONString(order));

            //用车时间-当前时间 = 时间差 - 30分钟 = 用车前30分钟距离现在的时间
            Integer time = Integer.parseInt((carTimeDate.getTime() - System.currentTimeMillis() - 30*60*1000)+"");
            rabbitTemplate.convertAndSend("taxi-order-delayEx3", "", id, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    message.getMessageProperties().setDelay(time);
                    return message;
                }
            });
        }

        return new Result(true,null,"SUCCESS");
    }

    @PostMapping("/takeOrder")
    public Result takeOrder(@RequestBody Order order){
        log.info("司机:{},抢单:{}",order.getCarCode(),order.getId());
        redisTemplate.opsForList().leftPush("takeOrder:"+order.getId(),order.getCarCode());
        return new Result(true, null, "报名成功,等待结果");
    }


    /**
     * 定时任务示例：每天凌晨12:00执行一次，查询所有司机信息并检查身份证有效期
     */
//    @Scheduled(cron = "0 0 0 * * ?")

    //每分钟运行
    @Scheduled(cron = "0 * * * * ?") // 每分钟运行
    public void checkDriverValidityPeriods() {
        List<driver> drivers = driverService.selectdriverList(new driver());
        for (driver d : drivers) {
            // 检查身份证有效期
            Date validityPeriodIdentityCard = d.getValidityPeriodIdentityCard();
            if (isWithin30Days(validityPeriodIdentityCard) || isExpired(validityPeriodIdentityCard)) {
                sendReminder(d, "身份证", validityPeriodIdentityCard);
            }

            // 检查驾驶证有效期
            Date validityPeriodDrivingLicense = d.getValidityPeriodDrivingLicense();
            if (isWithin30Days(validityPeriodDrivingLicense) || isExpired(validityPeriodDrivingLicense)) {
                sendReminder(d, "驾驶证", validityPeriodDrivingLicense);
            }
        }
    }


    /**
     * 判断日期是否在当前日期之后的30天内
     */
    private boolean isWithin30Days(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, 30);
        Date thirtyDaysLater = calendar.getTime();
        return date.after(new Date()) && date.before(thirtyDaysLater);
    }

    /**
     * 判断日期是否已经过期
     */
    private boolean isExpired(Date date) {
        return date.before(new Date());
    }

    /**
     * 发送提醒给用户
     */
    private void sendReminder(driver driver, String documentType, Date validityPeriod) {
        // 发送邮件提醒
        String to = driver.getEmailAddress();
        String subject = documentType + "有效期提醒";
        String text;
        if (isExpired(validityPeriod)) {
            text = "您的" + documentType + "有效期已经过期，请及时更换。";
        } else {
            text = "您的" + documentType + "有效期将在30天内到期，请及时更换。";
        }
        emailService.sendEmail(to, subject, text);

        // 打印日志
        System.out.println("Sending reminder to driver with ID: " + driver.getDriverId() + " for upcoming " + documentType + " validity period expiration.");
    }



}


